#include "camera.h"

Camera::Camera(float x, float y, float z, float pitch, float yaw, float roll, float fov, float aspectRatio, float zNear, float zFar)
{
	this->x = x;
	this->y = y;
	this->z = z;
	this->pitch = pitch;
	this->yaw = yaw;
	this->roll = roll;
	this->fov = fov;
	this->aspectRatio = aspectRatio;
	this->zNear = zNear;
	this->zFar = zFar;
}

Camera::~Camera()
{
}

void Camera::Move(float dx, float dz)
{
	this->x -= dx * sin(ToRadians(this->yaw - 90)) + dz * sin(ToRadians(this->yaw));
	this->z += dx * cos(ToRadians(this->yaw - 90)) + dz * cos(ToRadians(yaw));
}

void Camera::ProcessInput(Input* input, float cameraSpeed, float deltaTime, Vector3f playerSpeed, const Vector2f yLock)
{
	if(deltaTime <= 0)
		return;

	Vector2i mouseDelta = input->GetMouseDelta();
	float mouseDX = mouseDelta.x * cameraSpeed * 0.16f;
	float mouseDY = mouseDelta.y * cameraSpeed * 0.16f;

	if(this->yaw + mouseDX >= 360) {
		this->yaw = this->yaw + mouseDX - 360;
    } else if(this->yaw + mouseDX < 0) {
		this->yaw = 360 - this->yaw + mouseDX;
    } else {
		this->yaw += mouseDX;
    }

    if(this->pitch - mouseDY >= yLock.x && this->pitch - mouseDY <= yLock.y) {
		this->pitch += -mouseDY;
    } else if(this->pitch - mouseDY < yLock.x) {
		this->pitch = yLock.x;
    } else if(this->pitch - mouseDY > yLock.y) {
		this->pitch = yLock.y;
    }

	bool forward = input->GetKeyboardState()[DIK_W] & 0x80;
	bool backward = input->GetKeyboardState()[DIK_S] & 0x80;
	bool left = input->GetKeyboardState()[DIK_A] & 0x80;
	bool right = input->GetKeyboardState()[DIK_D] & 0x80;

	if (forward && right && !left && !backward) {
		Move(playerSpeed.x * deltaTime * 0.003f, -playerSpeed.z * deltaTime * 0.003f);
    }
    if (forward && left && !right && !backward) {
		Move(-playerSpeed.x * deltaTime * 0.003f, -playerSpeed.z * deltaTime * 0.003f);
    }
    if (forward && !left && !right && !backward) {
		Move(0, -playerSpeed.z * deltaTime * 0.003f);
    }
    if (backward && left && !right && !forward) {
		Move(-playerSpeed.x * deltaTime * 0.003f, playerSpeed.z * deltaTime * 0.003f);
    }
    if (backward && right && !left && !forward) {
		Move(playerSpeed.x * deltaTime * 0.003f, playerSpeed.z * deltaTime * 0.003f);
    }
    if (backward && !forward && !left && !right) {
		Move(0, playerSpeed.z * deltaTime * 0.003f);
    }
    if (left && !right && !forward && !backward) {
		Move(-playerSpeed.x * deltaTime * 0.003f, 0);
    }
    if (right && !left && !forward && !backward) {
		Move(playerSpeed.x * deltaTime * 0.003f, 0);
    }
}

void Camera::SetupProjectionMatrix(int type, Vector2i screenSize)
{
	switch(type) {
	case PERSPECTIVE:
		glPushAttrib(GL_TRANSFORM_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(fov, aspectRatio, zNear, zFar);
        glPopAttrib();
		break;
	case ORTHOGRAPHIC:
		glPushAttrib(GL_TRANSFORM_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-aspectRatio, aspectRatio, -1, 1, 0, zFar);
        glPopAttrib();
		break;
	case TWODEE:
		glPushAttrib(GL_TRANSFORM_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, screenSize.x, screenSize.y, 0, -1, 1);
        glPopAttrib();
		break;
	}
}

void Camera::FlyUp(float yUp)
{
	this->y += yUp;
}

void Camera::FlyDown(float yDown)
{
	this->y -= yDown;
}

float Camera::GetX()
{
	return this->x;
}

float Camera::GetY()
{
	return this->y;
}

float Camera::GetZ()
{
	return this->z;
}

void Camera::SetPosition(Vector3f position)
{
	this->x = position.x;
	this->y = position.y;
	this->z = position.z;
}

float Camera::GetPitch()
{
	return this->pitch;
}

float Camera::GetYaw()
{
	return this->yaw;
}

float Camera::GetRoll()
{
	return this->roll;
}

void Camera::SetRotation(Vector3f rotation)
{
	this->pitch = rotation.x;
	this->yaw = rotation.y;
	this->roll = rotation.z;
}

float Camera::GetFOV()
{
	return this->fov;
}

void Camera::SetFOV(float fov)
{
	this->fov = fov;
}

float Camera::GetAspectRatio()
{
	return this->aspectRatio;
}

void Camera::SetAspectRatio(float aspectRatio)
{
	this->aspectRatio = aspectRatio;
}